﻿/*
Commerce by Onex – eCommerce software platform (www.ecommerce.byonex.com)
Copyright (C) 2008-2010 by Onex Group

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 
 */
using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.Web.Security;
using System.Web.UI.WebControls;
using ShopDAO;
using ShopModel;
using System.Resources;
using System.Reflection;

namespace ShopBLL
{
    public class OrderManager
    {
        private OrderDAO orderDao;
        private PaymentDAO paymentDao;
        private CustomerDAO customerDao;
        private InvoiceDAO invoiceDao;
        private ShipmentDAO shipmentDao;
        private VoucherDAO voucherDao;
        private static ResourceManager rm;
        
        
        private OrderManager()
        {
            orderDao = new OrderDAO();
            paymentDao = new PaymentDAO();
            customerDao = new CustomerDAO();
            invoiceDao = new InvoiceDAO();
            shipmentDao = new ShipmentDAO();
            voucherDao = new VoucherDAO();
        }

        static OrderManager()
        {
            rm = new ResourceManager("Resources.Language", Assembly.Load("App_GlobalResources"));
        }

        private static OrderManager _Instance;

        public static OrderManager Instance
        {
            get
            {
                if (_Instance == null)
                    _Instance = new OrderManager();

                return _Instance;
            }
        }

        #region Customer

        public Customer GetRealizationCustomer(int RealizationID)
        {
            return customerDao.GetRealizationCustomer(RealizationID);
        }

        public List<Customer> GetCustomersByRealizartionIDs(string RealizationIDs, int? languageID)
        {
            return customerDao.GetCustomersByRealizartionIDs(RealizationIDs, languageID);
        }

        public bool AddCustomerToProfile(Guid profileId, Customer customer)
        {
           return customerDao.AddCustomerToProfile(profileId, customer);
        }

        public Customer GetCustomerByUserId(Guid userId, int? languageID)
        {
            Customer result = customerDao.GetCustomerByUserId(userId, languageID);

            if (result != null)
            {
                result.SameAddress = (result.City == result.CompanyCity && result.Street == result.CompanyStreet && result.ZipCode == result.CompanyZipCode);
            }

            return result;
        }

        public ShopUser GetUserByUserId(Guid userId, int? languageID)
        {
            ShopUser result = null;
            MembershipUser user = Membership.GetUser(userId);
            if (user != null)
            {
                result = new ShopUser(user);
                result.Customer = GetCustomerByUserId(userId, languageID);
                result.Roles = Roles.GetRolesForUser(result.UserName);
            }

            return result;

        }

        public ShopUser GetUserByUserName(string userName, int? languageID)
        {
            ShopUser result = null;
            MembershipUser user = Membership.GetUser(userName);
            if (user != null)
            {
                result = new ShopUser(user);
                result.Customer = GetCustomerByUserId((Guid)user.ProviderUserKey, languageID);
                result.Roles = Roles.GetRolesForUser(userName);
            }
            return result;
        }

        public bool UpdateCustomer(Customer customer)
        {
            if (customer.IsCompany)
            {
                if (customer.SameAddress)
                {
                    customer.CompanyCity = customer.City;
                    customer.CompanyStreet = customer.Street;
                    customer.CompanyZipCode = customer.ZipCode;
                }
               /* else
                {
                    customer.CompanyCity = string.Empty;
                    customer.CompanyStreet = string.Empty;
                    customer.CompanyZipCode = string.Empty;
                }*/
            }
            else
            {
                customer.CompanyName = string.Empty;
                customer.CompanyNIP = string.Empty;
                customer.CompanyCity = string.Empty;
                customer.CompanyStreet = string.Empty;
                customer.CompanyZipCode = string.Empty;
            }
            return customerDao.UpdateCustomer(customer);
        }

        public List<ShopUser> GetUsers(bool shopService,string lastName,string email,string address,bool accountApproved,bool accountLocked, int? languageID)
        {
            return customerDao.GetUsers( shopService, lastName, email, address, accountApproved, accountLocked,  languageID);
        }

        public Dictionary<string, string> GetAllRoles()
        {
            return customerDao.GetAllRoles();
        }

        public Dictionary<string, string> GetAllServiceRoles()
        {
            return customerDao.GetAllServiceRoles();
        }

        #endregion Customer

        #region Realization

        public int NewOrder(ref Realization order, object userId, bool createNewAccount)
        {
            //zmiany dla poprawnego zapisu na bazie bo w orderData pamietane są dane które urzytkownik wpisał także jeśli z nich zrezygnuje np. odznaczy faktur VAT
            if (!order.SendAbroad)
            {
                order.iCustomer.Country = "Polska";
                order.iCustomer.CountryID = -1;
            }
            if (order.iCustomer.IsCompany)
            {
                if (order.iCustomer.SameAddress)
                {
                    
                    order.iCustomer.CompanyCity = order.iCustomer.City;
                    order.iCustomer.CompanyStreet = order.iCustomer.Street;
                    order.iCustomer.CompanyZipCode = order.iCustomer.ZipCode;
                }
            }
            else
            {
                order.iCustomer.CompanyCity = string.Empty;
                order.iCustomer.CompanyName = string.Empty;
                order.iCustomer.CompanyNIP = string.Empty;
                order.iCustomer.CompanyStreet = string.Empty;
                order.iCustomer.CompanyZipCode = string.Empty;
            }
            

            return orderDao.NewOrder(order.iCustomer.FirstName, order.iCustomer.Surname, order.iCustomer.Street, order.iCustomer.City, order.iCustomer.ZipCode, order.iCustomer.CountryID,
                order.iCustomer.Email, order.iCustomer.Phone, order.iCustomer.PreferedLanguageID, order.iCustomer.CompanyName, order.iCustomer.CompanyNIP, order.iCustomer.CompanyStreet, order.iCustomer.CompanyCity, order.iCustomer.CompanyZipCode,
                order.Payment.PaymentID, order.ShipmentID, order.ShipmentCost, HttpContext.Current.Session.SessionID, order.TotalAmountNetto + order.ShipmentCost, order.Info, order.UrlReferer, userId, createNewAccount, order.OtherAddress, (order.Voucher!=null)?(int?)order.Voucher.IdVoucher:null, order.iCustomer.NewsSubscription);
        }

        public List<Realization> GetDelayedPayments()
        {
            return orderDao.GetDelayedPayments();
        }

        public bool SetPaymentNotificationSent(int RealizationID, bool Sent)
        {
            return orderDao.SetPaymentNotificationSent(RealizationID, Sent);
        }

        public bool CheckIfSpecimensMissing(int RealizationID)
        {
            return orderDao.CheckIfSpecimensMissing(RealizationID);
        }

        public void CancelRealization(int RealizationID)
        {
            orderDao.CancelRealization(RealizationID);
        }

        public bool UpdateRealization(int IDRealization, DateTime EndDate, string TransferID, string Info, string UrlReferer, int PaymentID, decimal ShipmentCost, decimal ShipmentRealCost, bool PaymentNotificationSent, int statusID, int ShipmentID, DateTime? InvoiceDate, DateTime? DelayedPaymentDate)
        {
            return orderDao.UpdateRealization(IDRealization, EndDate, TransferID, statusID, Info, UrlReferer, PaymentID, ShipmentCost, ShipmentRealCost, PaymentNotificationSent, ShipmentID, InvoiceDate, DelayedPaymentDate);
        }

        public void UpdateRealizationSetPaid(int RealizationID, RealizationStatus status, string TransferID)
        {
            orderDao.UpdateRealizationSetPaid(RealizationID, (int)status, TransferID);
        }

        public void UpdateRealizationSetDelayedPayment(int realizationID)
        {
            orderDao.UpdateRealizationSetDelayedPayment(realizationID);
        }

        public void UpdateRealizationSetSend(int RealizationID, RealizationStatus status, DateTime EndDate, decimal ShipmentCost)
        {
            orderDao.UpdateRealizationSetSend(RealizationID, (int)status, EndDate, ShipmentCost);
        }

        public void UpdateRealizationSetStatus(int realizationID, RealizationStatus status)
        {
            orderDao.UpdateRealizationSetStatus(realizationID, (int)status);
        }

        public void UpdateRealizationSetFinished(int RealizationID)
        {
            orderDao.UpdateRealizationSetFinished(RealizationID);
        }

        public Realization GetRealizationDetails(int RealizationID)
        {
            return orderDao.GetRealizationDetails(RealizationID);
        }

        public Realization GetRealizationAllDetails(int RealizationID, int? LanguageID)
        {
            return orderDao.GetRealizationAllDetails(RealizationID, LanguageID);
        }

        public Realization GetLastRealization()
        {
            return orderDao.GetLastRealization();
        }

        public List<Realization> GetRealizationList(string Customer, string ID, string PaymentType, string StatusID, string OnlyActive, ref int pageNumber, int pageSize, out int orderCount, string ProductId)
        {
            return orderDao.GetRealizationList(Customer, ID, PaymentType, StatusID, OnlyActive, ref pageNumber, pageSize, out orderCount, ProductId);
        }

        public List<Realization> GetRealizationList(int StatusID, ref int pageNumber, int pageSize, out int orderCount, bool? IncludeMissing)
        {
            return orderDao.GetRealizationList(StatusID, ref pageNumber, pageSize, out orderCount, IncludeMissing);
        }

        public List<Realization> GetRealizationListForCustomer(Guid userId, bool onlyActiv)
        {
            return orderDao.GetRealizationListForCustomer(userId, onlyActiv);
        }

        public List<Realization> GetRealizationsWithMissingProducts(int? LanguageID)
        {
            return orderDao.GetRealizationsWithMissingProducts( LanguageID);
        }

        public List<RealizationLog> GetRealizationLog(int RealizationID)
        {
            return orderDao.GetRealizationLog(RealizationID);
        }
		
        public bool UpdateRealizationAddress(int IDRealizationAddress, string FirstName, string Surname, string Street, string ZipCode, string City, int CountryID)
        {
            return orderDao.UpdateRealizationAddress(IDRealizationAddress, FirstName, Surname, Street, ZipCode, City, CountryID);
        }

        public List<ListItem> GetAllRealizationStatus()
        {
            List<ListItem> result = new List<ListItem>();
            foreach (int i in orderDao.GetAllStatusIDs())
            {
                result.Add(new ListItem(CommonTools.GetStatusString(i), i.ToString()));
            }

            return result;
        }

        #endregion Realization

        #region OrderedProducts

        public void AddProductToRealization(int RealizationID, int ProductID, int Count)
        {
            orderDao.AddProductToRealization(RealizationID, ProductID, Count);
        }

        public void RemoveProductFromRealization(int RealizationID, int ProductID, int StatusID, int Count)
        {
            orderDao.RemoveProductFromRealization(RealizationID, ProductID, StatusID, Count);
        }

        public void CancelOrderedProduct(int RealizationID, int ProductID, int StatusID, int Count)
        {
            orderDao.CancelOrderedProduct(RealizationID, ProductID, StatusID, Count);
        }

        public void ReturnOrderedProduct(int RealizationID, int ProductID, int StatusID, int Count)
        {
            orderDao.ReturnOrderedProduct(RealizationID, ProductID, StatusID, Count);
        }

        public void UpdateRealizationMissingSpecimens(int RealizationID)
        {
            orderDao.UpdateRealizationMissingSpecimens(RealizationID);
        }

        public void UptateOrderedProductPrice(int RealizationID, int ProductID, decimal NewPrice)
        {
            orderDao.UptateOrderedProductPrice(RealizationID, ProductID, NewPrice);
        }

        public List<ProductBatch> GetMissingProductsList(int? LanguageID)
        {
            return orderDao.GetMissingProductsList(LanguageID);
        }
        
        public List<ProductBatch> GetRealizationMissingProductsList(int RealizationID, int? LanguageID)
        {
            return orderDao.GetRealizationMissingProductsList(RealizationID, LanguageID);
        }

        public List<ProductBatch> GetRealizationOrderedProductsList(int RealizationID, int? LanguageID)
        {
            return orderDao.GetRealizationOrderedProductsList(RealizationID, LanguageID);
        }

        public void IncludeVoucherDiscount(int RealizationID, int VoucherId)
        {
            orderDao.IncludeVoucherDiscount(RealizationID, VoucherId);
        }

        #endregion OrderedProducts

        #region Invoice

        public int GetInvoiceNumber()
        {
            return invoiceDao.GetInvoiceNumber();
        }

        public void UpdateInvoiceNumber(int newInvoiceNumber)
        {
            invoiceDao.UpdateInvoiceNumber(newInvoiceNumber);
        }

        public bool CreateInvoice(int RealizationID, bool RenewInvoiceNumber)
        {
            return invoiceDao.CreateInvoice(RealizationID, RenewInvoiceNumber);
        }


        #endregion Invoice

        #region Payment

        public bool SavePaymentType(int id, string name, bool active, string type, string code, string icon, int? languageID)
        {
            return paymentDao.SavePaymentType(id, name, active, type, code, icon, languageID);
        }

        public bool DeletePaymentType(int id)
        {
            return paymentDao.DeletePaymentType(id);
        }

        public List<PaymentType> GetPaymentTypes(bool forClient, bool onlyActive, int? languageID)
        {
            return paymentDao.GetPaymentTypes(forClient, onlyActive, languageID);
        }

        public List<PaymentType> GetPaymentTypes(bool forClient, bool onlyActive, bool IncludeShipmentPossibilities, int? languageID)
        {
            List<PaymentType> result = paymentDao.GetPaymentTypes(forClient, onlyActive, languageID);

            if (IncludeShipmentPossibilities)
            {
                foreach (PaymentType p in result)
                    p.ShipmentPosibilities = shipmentDao.GetShipmentPossibilities(p.PaymentID, languageID);
            }

            return result;
        }

        public PaymentGroups GetPaymentGroup(int PaymentID)
        {
            string PaymentType = paymentDao.GetPaymentTypeName(PaymentID);

            switch (PaymentType)
            {
                case "Instalment": return PaymentGroups.Instalment;
                case "Delivery": return PaymentGroups.Delivery;
                case "Online": return PaymentGroups.Online;
                case "Transfer": return PaymentGroups.Transfer;
                case "Delayed": return PaymentGroups.DelayedPayment;
                default: return PaymentGroups.Transfer;
            }
        }

        public string GetPaymentGroupString(PaymentGroups PaymentGroup)
        {
            switch (PaymentGroup)
            {
                case PaymentGroups.Delivery: return rm.GetString("ShipmentWithPay");
                case PaymentGroups.Instalment: return rm.GetString("Instalements");
                case PaymentGroups.Transfer: return rm.GetString("Transfer");
                case PaymentGroups.Online: return rm.GetString("OnlinePayment");
                case PaymentGroups.DelayedPayment: return rm.GetString("DelayedPaymentStatus");
                default: return string.Empty;
            }
        }

        //public PaymentGroups GetPaymentGroup(string paymentGroupString)
        //{
        //    if (paymentGroupString == rm.GetString("ShipmentWithPay")) return PaymentGroups.Delivery;
        //    if (paymentGroupString == rm.GetString("Instalements")) return PaymentGroups.Instalment;
        //    if (paymentGroupString == rm.GetString("Transfer")) return PaymentGroups.Transfer;
        //    if (paymentGroupString == rm.GetString("OnlinePayment")) return PaymentGroups.Online;
        //    return PaymentGroups.Unknown;
        //}

        public PaymentType GetPaymentType(int PaymentID, int? languageID)
        {
            return paymentDao.GetPaymentType(PaymentID, languageID);
        }

        public string GetPaymentName(int paymentID)
        {
            string PaymentType = paymentDao.GetPaymentTypeName(paymentID);

            switch (PaymentType)
            {
                case "Instalment": return rm.GetString("Instalements");
                case "Delivery": return rm.GetString("ShipmentWithPay");
                case "Online": return rm.GetString("OnlinePayment");
                case "Transfer": return rm.GetString("Transfer");
                default: return rm.GetString("Transfer");
            }
        }

        #endregion Payment

        #region Shipment

        public bool SaveShipmentPossibility(int PaymentID, int ShipmentID)
        {
            return shipmentDao.SaveShipmentPossibility(PaymentID, ShipmentID);
        }

        public bool DeleteShipmentPossibility(int PaymentID, int ShipmentID)
        {
            return shipmentDao.DeleteShipmentPossibility(PaymentID, ShipmentID);
        }

        public List<ShipmentType> GetShipmentPossibilities(int PaymentID, int? languageID)
        {
           return shipmentDao.GetShipmentPossibilities(PaymentID, languageID); 
        }

        public bool SaveShipmentType(int? ShipmentID, string Name, decimal CountryShipmentPrice, decimal EUShipmentPrice, decimal WorldShipmentPrice, int? languageID)
        {
            return shipmentDao.SaveShipmentType(ShipmentID, Name, CountryShipmentPrice, EUShipmentPrice, WorldShipmentPrice, languageID);
        }

        public bool DeleteShipmentType(int ShipmentID)
        {
            return shipmentDao.DeleteShipmentType(ShipmentID);
        }

        public List<ShipmentType> GetShipmentTypes(int? languageID)
        {
            return shipmentDao.GetShipmentTypes(languageID);
        }

        public ShipmentType GetShipmentType(int ShipmentID, int? languageID)
        {
            return shipmentDao.GetShipmentType(ShipmentID, languageID);
        }

        public bool CheckShipmentPossiblities(int shipmentID, int paymentId, int countryID)
        {
            return shipmentDao.CheckShipmentPossiblities(paymentId, shipmentID, countryID);
        }

        #endregion Shipment

        #region Vouchers

        public List<ListItem> GetAllVoucherTypes()
        {
            List<ListItem> result = new List<ListItem>();
            foreach (int i in voucherDao.GetAllVoucherTypesIDs())
            {
                result.Add(new ListItem(CommonTools.GetVoucherTypeString(i), i.ToString()));
            }

            return result;
        }

        public int SaveVoucher(Voucher Voucher)
        {
            return voucherDao.SaveVoucher(Voucher);
        }

        public List<Voucher> GetCustomerVouchers(int CustomerId)
        {
            return voucherDao.GetCustomerVouchers(CustomerId);
        }

        public Voucher GetGeneratedRealizationVoucher(int RealizationId)
        {
            return voucherDao.GetGeneratedRealizationVoucher(RealizationId);
        }

        public Voucher GetUsedRealizationVoucher(int RealizationId)
        {
            return voucherDao.GetUsedRealizationVoucher(RealizationId);
        }

        public Voucher GetVoucherByGuid(string VoucherCode, bool? Used)
        {
            return voucherDao.GetVoucherByGuid(VoucherCode.Replace("-", "").Substring(0, 8), Used);
        }

        public List<BasketItem> IncludeVoucherToOrder(List<BasketItem> basket, Voucher voucher)
        {            
            List<BasketItem> newBasket = new List<BasketItem>();
            if (basket != null && voucher != null)
            {
                switch (voucher.Type)
                {
                    case VoucherType.Percent:
                        {
                            foreach (BasketItem bi in basket)
                            {
                                newBasket.Add(new BasketItem(bi.ProductId,bi.Name,bi.PriceBrutto*(voucher.Value.Value/100m),bi.Count,bi.VatRateValue));
                            }
                            break;
                        }
                    case VoucherType.Value:
                        {
                            int items = basket.Count;
                            decimal defaultDiscount = voucher.Value.Value / items;
                            decimal price = 0;
                            decimal surplus = 0;
                            foreach (BasketItem bi in basket)
                            {
                                price = (bi.PriceBrutto - defaultDiscount-surplus)/bi.Count;
                                if (price < 1)
                                {
                                    surplus += Math.Abs((bi.PriceBrutto - defaultDiscount - surplus) / bi.Count) - 1;
                                    price = 1;
                                }
                                newBasket.Add(new BasketItem(bi.ProductId, bi.Name, price, bi.Count, bi.VatRateValue));
                            }
                            break;
                        }
                }
            }
            return newBasket;
        }

        public List<Voucher> GetVouchers(ref int pageNumber, int pageSize, out int Count, bool used)
        {
            return voucherDao.GetVouchers(ref pageNumber, pageSize, out Count, used);
        }

        public bool GenerateVouchers(Voucher Voucher, int count)
        {
            return voucherDao.GenerateVouchers(Voucher, count);
        }
        public List<Voucher> GetVouchersByIDs(string IDs)
        {
            return voucherDao.GetVouchersByIDs(IDs);
        }

        public List<Voucher> GetLastGeneratedVouchers()
        { 
            return voucherDao.GetLastGeneratedVouchers(); 
        }

        #endregion Vouchers
    }
}
